// TelnetCommandInterpreter.cpp: implementation of the CTelnetCommandInterpreter class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "AnsiTerminal.h"
#include "TelnetCommandInterpreter.h"

#include "WillCommand.h"
#include "WontCommand.h"
#include "DoCommand.h"
#include "DontCommand.h"
#include "UnknownCommand.h"
#include "SubnegotiationCommand.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

// const char IAC = char(255);
// const char WILL = char(251);
// const char WONT = char(252);
// const char DO = char(253);
// const char DONT = char(254);
// 
// const char SB = char(250);
// const char SE = char(240);
// 
// const char NOP = char(241);
// 
// const char GO_AHEAD = char(249);
// const char ERASE_LINE = char(248);
// const char ERASE_CHARACTER = char(247);
// const char ARE_YOU_THERE = char(246);
// const char ABORT_OUTPUT = char(245);
// const char INTERRUPT_PROCESS = char(244);
// const char BREAK = char(243);
// const char DATA_MARK = char(242);


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CTelnetCommandInterpreter::CTelnetCommandInterpreter(ITelnetDataSender *pTelnetDataSender, ITelnetOptionCollection *pOptionCol)
{
	m_pTelnetDataSender = pTelnetDataSender;
	m_pOptionCol = pOptionCol;
	m_pCurCommand = NULL;
	m_bProcessing = FALSE;
	m_pTelnetLogger = NULL;
	m_commandCharCount = 0;
}

CTelnetCommandInterpreter::~CTelnetCommandInterpreter()
{
	delete m_pCurCommand;
}

BOOL CTelnetCommandInterpreter::EatChar(char c)
{
	if(m_pCurCommand)
	{
		if(m_pCurCommand->EatChar(c))
		{
			++m_commandCharCount;
			return TRUE;
		}
		else
		{
			if(m_pTelnetLogger)
			{
				LogType type = LOG_COMMAND;
				CSubnegotiationCommand *pSubCommand = dynamic_cast<CSubnegotiationCommand*>(m_pCurCommand);
				if(pSubCommand)
				{
					type = LOG_OPTION;
				}
				m_pTelnetLogger->AddLogPoint(DIR_RECEIVE, type, m_commandCharCount, m_logSlot);
			}
			m_commandCharCount = 0;

			m_bProcessing = FALSE;
			setCurCommand(NULL);
		}
	}

	if(!m_bProcessing)
	{
		if(c == IAC)
		{
			m_bProcessing = TRUE;
			++m_commandCharCount;
			ASSERT(m_commandCharCount == 1);
			return TRUE;
		}
		return FALSE;
	}
	
	// IAC ing...
	switch(c)
	{
	case WILL:
		setCurCommand(new CWillCommand(m_pOptionCol));
		break;
	case WONT:
		setCurCommand(new CWontCommand(m_pOptionCol));
		break;
	case DO:
		setCurCommand(new CDoCommand(m_pOptionCol));
		break;
	case DONT:
		setCurCommand(new CDontCommand(m_pOptionCol));
		break;
	case SB:
		setCurCommand(new CSubnegotiationCommand(m_pOptionCol));
		break;
	case SE:
		setCurCommand(new CUnknownCommand());
		break;
	case NOP:
		setCurCommand(new CUnknownCommand());
		break;
	case IAC:
		m_commandCharCount = 0;
		m_bProcessing = FALSE;
		return FALSE;
	default:
		setCurCommand(new CUnknownCommand());
	}
	++m_commandCharCount;

	//m_logSlot = -1;
	if(m_pTelnetLogger)
	{
		m_logSlot = m_pTelnetLogger->AddSlot();
	}
	
	return TRUE;
}

void CTelnetCommandInterpreter::setCurCommand(CTelnetCommand *pCommand)
{
	delete m_pCurCommand;
	m_pCurCommand = pCommand;
}

void CTelnetCommandInterpreter::SetTelnetLogger(CTelnetLogger *pTelnetLogger)
{
	m_pTelnetLogger = pTelnetLogger;
}